(defclass game-obj ()
  ((lt    :accessor lt    :initarg :lt)   ; Координаты верхнего левого угла заданы комплексным числом
   (rb    :accessor rb    :initarg :rb)   ; Координаты нижнего правого угла заданы комплексным числом
   (color :accessor color :initarg :color)
   (rect  :accessor rect  :initarg :rect)))

(defmethod x ((coords number))
    (if (complexp coords)
        (realpart coords)
        coords))

(defmethod y ((coords number))
    (if (complexp coords)
        (imagpart coords)
        0))

(defmethod x ((coords list))
    (first coords))

(defmethod y ((coords list))
    (second coords))

(defmethod width ((obj game-obj))
    (abs (- (x (lt obj))
            (x (rb obj)))))

(defmethod height ((obj game-obj))
    (abs (- (y (rb obj))
            (y (lt obj)))))

(defun list-to-complex (list)
    (complex (first  list)
             (second list)))

(defun update-rect (g-o)
    (setf (sdl2:rect-x (rect g-o)) (floor (x (lt g-o))))
    (setf (sdl2:rect-y (rect g-o)) (floor (y (lt g-o)))))

(defun color-list-to-sdl-color (color surf)
    (apply #'sdl2:map-rgb (sdl2:surface-format surf) color))

(defun new-game-obj (&key (coords '(0 0)) ;Если поставить в эту переменную '(0 0) , вылазит ошибка.
                          (width  1)
                          (height nil)
                          (color  '(0 0 0 255)))
    (setf coords (list-to-complex coords))
    (unless height
        (setf height width))
    (let* ((dimentions (complex width height)) 
           (g-o (make-instance 'game-obj :lt coords
                                         :rb (+ coords dimentions)
                                         :color color)))
        (setf (rect g-o) (sdl2:make-rect (x      (lt  g-o))
                                         (y      (lt  g-o))
                                         (width  g-o)
                                         (height g-o)))
        g-o))

(defmacro with-renderer-draw-color ((renderer r g b a) &body body)
    "Use this macro to temporary set the color used for drawing operations (Rect, Line and Clear)."
    (alexandria:with-gensyms (rv gv bv av)
    `(multiple-value-bind (,rv ,gv ,bv ,av) (sdl2:get-render-draw-color ,renderer)
         (sdl2:set-render-draw-color ,renderer ,r ,g ,b ,a)
         (unwind-protect
              (progn ,@body)
             (sdl2:set-render-draw-color ,renderer ,rv ,gv ,bv ,av)))))



(defun draw-game-obj (g-o renderer)
    (let ((color (color g-o)))
        (with-renderer-draw-color (renderer (first  color)
                                            (second color)
                                            (third  color)
                                            (fourth color))
            (update-rect g-o)
            (sdl2:render-fill-rect renderer
                                   (rect g-o)))))



(defmethod width  ((window sdl2-ffi:sdl-window))
    (sdl2:get-window-size window))

(defmethod height ((window sdl2-ffi:sdl-window))
    (second (multiple-value-list (sdl2:get-window-size window))))

(defmethod collision-p ((a game-obj) (b game-obj))
    (and (or (< (x (lt a))
                (x (lt b))
                (x (rb a)))
             (< (x (lt a))
                (x (rb b))
                (x (rb a))))
         
         (or (< (y (lt a))
                (y (lt b))
                (y (rb a)))
             (< (y (lt a))
                (y (rb b))
                (y (rb a))))))

(defmethod teleport! ((g-o game-obj) (coords list))
    (let ((bias (complex (width  g-o)
                         (height g-o)))
          (coords (list-to-complex coords)))
        (setf (lt g-o) coords)
        (setf (rb g-o) (+ coords bias))))

(defun random-from-range (min max)
    (+ (random (- max min)) min))

(defmethod random-teleport! ((g-o game-obj) (left-top list) (right-bottom list))
    (teleport! g-o (list (random-from-range (x left-top)
                                            (x right-bottom))
                         (random-from-range (y left-top)
                                            (y right-bottom)))))

(defun random-teleport-on-screen! (g-o win)
    (random-teleport! g-o
                      (list 0 0)
                      (list (- (width  win)
                               (width  g-o))
                            (- (height win)
                               (height g-o)))))

(defmethod move! ((g-o game-obj) (dir list))
    (let ((dir (list-to-complex dir)))
        (incf (lt g-o) dir)
        (incf (rb g-o) dir)))

(defun fill-surface (surface color)
    (sdl2:fill-rect surface
                    nil
                    (apply #'sdl2:map-rgb (sdl2:surface-format surface) color)))

(defparameter *screen-width*  640)
(defparameter *screen-height* 480)

(defun game ()
    (sdl2:with-init (:video)
        (sdl2:with-window (win :title "Ешь яблоки"
                                :w *screen-width*
                                :h *screen-height*
                                :flags '(:shown :resizable))
            (let* ((render (sdl2:create-renderer win -1))
                   (player (new-game-obj :width 64 :color '(0 255 0 255)))
                   (apple  (new-game-obj :width 32 :color '(255 0 0 255)))
                   (back-color '(10 160 200 255))
                   (speed  0.8)
                   (velocity (list 0 speed))
                   (score 0))
                (random-teleport-on-screen! apple win)
                (apply #'sdl2:set-render-draw-color render back-color)
                (sdl2:with-event-loop ()
                    (:quit () t)
                    (:keydown (:keysym keysym)
                              (case (sdl2:scancode keysym)
                                (:scancode-up    (setf velocity (list 0
                                                                      (- speed))))
                                (:scancode-right (setf velocity (list speed
                                                                      0)))
                                (:scancode-left  (setf velocity (list (- speed)
                                                                      0)))
                                (:scancode-down  (setf velocity (list 0
                                                                      speed)))
                                (:scancode-space (setf velocity (list 0
                                                                      0)))))
                    (:idle ()
                           (sdl2:render-clear render)
                           (draw-game-obj apple  render)
                           (draw-game-obj player render)
                           (when (collision-p player apple)
                               (incf score)
                               (random-teleport-on-screen! apple win))
                           (move! player velocity)
                           (sdl2:render-present render)))))))
 
